<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */
namespace app\service\analysis\data\video;

use app\enum\AnalysisEnum;
use app\enum\CommonEnum;
use app\model\mongo\MongoReportModel;
use app\service\analysis\report\ReportVideoService;
use app\service\BaseService;
use think\Collection;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Cache;

final class VideoDayReportService extends BaseService
{
    /**
     * @var int 队列最大长度
     */
    private const MAX_LEN = 600;

    /**
     * @var int 媒体id
     */
    private int $mediaId;

    /**
     * @var null|ReportVideoService 账户服务
     */
    private ?ReportVideoService $service;

    /**
     * @var null|MongoReportModel 日报模型
     */
    private ?MongoReportModel $report;

    /**
     * @var mixed|string 缓存键值
     */
    private string $queueKey = AnalysisEnum::TASK_QUEUE_LIST['video_account_day_stat'];

    public function __construct(int $mediaId = 0)
    {
        $this->mediaId = $mediaId;
        $this->service = new ReportVideoService($this->mediaId);
    }

    /**
     * 是否是日报服务
     */
    public function isService(): bool
    {
        return $this->service->isService();
    }

    /**
     * 获取待同步列表.
     *
     * @return array|Collection|MongoReportModel[]
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getList()
    {
        $redis = Cache::store('redis')->handler();
        if ($this->queueKey) {
            $len = $redis->hLen($this->queueKey);
            if ($len > self::MAX_LEN) {
                return [];
            }
        } else {
            return [];
        }
        return $this->service->getWaitDayList();
    }

    public function runTask(MongoReportModel $model): bool
    {
        $this->report = $model;
        if (! $this->report->getKey()) {
            return self::setError('未知日报数据');
        }

        if (! $this->checkProperty()) {
            return $this->setReportFix();
        }

        if (! $this->setDayStat()) {
            return self::setError('设置账户汇总失败');
        }

        return $this->setReportSync();
    }

    /**
     * 属性检查.
     */
    private function checkProperty(): bool
    {
        if (empty($this->report->getAttr('company_id'))) {
            return self::setError('未知企业');
        }
        if (empty($this->report->getAttr('client_id'))) {
            return self::setError('未知客户');
        }
        if (empty($this->report->getAttr('stat_date'))) {
            return self::setError('未知汇总日期');
        }
        if (empty($this->report->getAttr('signature'))) {
            return self::setError('未知MD5值');
        }
        if ($this->mediaId == CommonEnum::KS_MEDIA && empty($this->report->getAttr('user_id'))) {
            return self::setError('未知用户');
        }
        return true;
    }

    /**
     * 设置日汇总数据.
     */
    private function setDayStat(): bool
    {
        $redis = Cache::store('redis')->handler();
        if ($this->queueKey) {
            $field = md5(json_encode([$this->report->getAttr('account_id'), $this->report->getAttr('video_id')]));
            if (! $redis->hExists($this->queueKey, $field)) {
                $redis->hSetnx($this->queueKey, $field, json_encode([strval($this->report->getAttr('_id')), $this->mediaId]));
            }
        }
        return true;
    }

    /**
     * 设置日报修复状态.
     */
    private function setReportFix(): bool
    {
        $this->report->setAttr('is_sync', MongoReportModel::SYNC_FIX);
        return $this->report->save();
    }

    /**
     * 设置日报同步完成.
     */
    private function setReportSync(): bool
    {
        $this->report->setAttr('is_sync', MongoReportModel::SYNC_YES);
        return $this->report->save();
    }
}
